#include "character.h"
#include "containerWrapper.h"
#include "behaviour.h"

#include "createCustomClasses.h"
#include "deleteCustomClasses.h"


Character::~Character()
{
	delete behavioursAvailable;
}

ActionList* Character::update(StackI* _immediate, StackI* _shortTerm, StackI* _longTerm, float _deltaSeconds)
{
	//Don't think I need this - stack update is performed in arbitrator

	return NULL;
}



Behaviour* Character::getCurrentBehaviour(StackI* _behaviourStack)
{
	if (!_behaviourStack->isEmpty())
		return _behaviourStack->peek();


	return NULL;
}


bool Character::processEvents(EventList* _events, StackI* _immediate, StackI* _shortTerm, StackI* _longTerm)
{

	BehaviourList* newBehaviours = new BehaviourList();

	bool immediateStackIncrease = false;
	bool shortTermStackIncrease = false;
	bool longTermStackIncrease = false;


	//Generate behaviours from events
	for (int i = 0; i < _events->getSize(); i++)
	{
		Behaviour* newBehaviour = getHighestPriorityBehaviour(_events->getAt(i));

		//Check if behaviour could be generated from event
		if (newBehaviour != NULL)
		{
			newBehaviours->add(newBehaviour);
		}
		else
		{
			//No behaviour generated - cleanup Event
			DeleteCustomClass::Delete(_events->getAt(i));
		}
		//Null event so not deleted during list deconstruction
		_events->setToNull(i);
	}

	_events->emptyList();

	//order list in priority order
	sortBehaviourListOnPriority(newBehaviours);

	//Add behaviours to stack if they are higher priority than current stuff
	for (int i = 0; i < newBehaviours->getSize(); i++)
	{

		switch (newBehaviours->getAt(i)->getStack())
		{
		case Stacks::immediate:
			if (_immediate->isEmpty())
			{
				_immediate->push(newBehaviours->getAt(i));
				newBehaviours->nullWithoutRemoving(i);
				immediateStackIncrease = true;
			}
			else if (getBehaviourInternalPriorityValue(_immediate->peek()->getBehaviourType()) < getBehaviourInternalPriorityValue(newBehaviours->getAt(i)->getBehaviourType()))
			{
				_immediate->push(newBehaviours->getAt(i));
				newBehaviours->nullWithoutRemoving(i);
				immediateStackIncrease = true;
			}
		break;

		case Stacks::shortTerm:
			if (_shortTerm->isEmpty())
			{
				_shortTerm->push(newBehaviours->getAt(i));
				newBehaviours->nullWithoutRemoving(i);
				shortTermStackIncrease = true;
			}
			else if (getBehaviourInternalPriorityValue(_shortTerm->peek()->getBehaviourType()) < getBehaviourInternalPriorityValue(newBehaviours->getAt(i)->getBehaviourType()))
			{
				_shortTerm->push(newBehaviours->getAt(i));
				newBehaviours->nullWithoutRemoving(i);
				shortTermStackIncrease = true;
			}
		break;

		case Stacks::longTerm:
			if (_longTerm->isEmpty())
			{
				_longTerm->push(newBehaviours->getAt(i));
				newBehaviours->nullWithoutRemoving(i);
				longTermStackIncrease = true;
			}
			else if (getBehaviourInternalPriorityValue(_longTerm->peek()->getBehaviourType()) < getBehaviourInternalPriorityValue(newBehaviours->getAt(i)->getBehaviourType()))
			{
				_longTerm->push(newBehaviours->getAt(i));
				newBehaviours->nullWithoutRemoving(i);
				longTermStackIncrease = true;
			}
		break;
		}
	}

	bool activeBehaviourChanged = false;

	//Check if highest priority stack changed - generate new actions if true
	if (immediateStackIncrease)
	{
		activeBehaviourChanged = true;
	}
	else if (shortTermStackIncrease)
	{
		if (_immediate->isEmpty())
			activeBehaviourChanged = true;
	}
	else if (longTermStackIncrease)
	{
		if (_immediate->isEmpty() && _shortTerm->isEmpty())
			activeBehaviourChanged = true;
	}

	//Cleanup new behaviours not added to stack
	delete newBehaviours;

	return activeBehaviourChanged;
}



Behaviour* Character::getHighestPriorityBehaviour(Event* _event)
{
	//return if either list is empty - can't compare
	if (_event->numberOfResponses < 1)
		return NULL;

	if (numberOfBehaviours < 1)
		return NULL;

	//Container for storing behaviours matching in Character and Event list
	BehaviourList newBehaviours = BehaviourList();

	int highestPriorityValue = 0;

	//Store Behaviours that match + increase highestPriority if higher than previous
	for (int i = 0; i < numberOfBehaviours; i++)
	{
		for (int j = 0; j < _event->numberOfResponses; j++)
		{
			if (behavioursAvailable[i].behaviourType == _event->responses[j])
			{
				newBehaviours.add(CreateCustomClasses::createBehaviour(behavioursAvailable[i].behaviourType));

				if (behavioursAvailable[i].priority > highestPriorityValue)
					highestPriorityValue = behavioursAvailable[i].priority;
			}
		}
	}

	//No matches, cleanup and return
	if (newBehaviours.getSize() == 0)
	{
		return NULL;
	}


	int highestBehaviourPriorityValue = 0; // stores highest priority value from actual behaviour priority
	
	//prune behaviours from newbehaviour list which are below HighestPriorityValue
	for (int i = 0; i < newBehaviours.getSize(); i++)
	{
		if (getBehaviourInternalPriorityValue(newBehaviours.getAt(i)->getBehaviourType()) < highestPriorityValue)
			newBehaviours.removeAt(i--);
		else
		{
			if (newBehaviours.getAt(i)->getBehaviourPriorityValue() > highestBehaviourPriorityValue)
			{
				highestBehaviourPriorityValue = newBehaviours.getAt(i)->getBehaviourPriorityValue();
			}
		}
	}

	//prune final behaviours from newbehaviour list for lowest BehaviourPriority value
	for (int i = 0; i < newBehaviours.getSize(); i++)
	{
		if (newBehaviours.getAt(i)->getBehaviourPriorityValue() != highestBehaviourPriorityValue)
		{
			newBehaviours.removeAt(i);
		}
	}

	//newBehaviours should have 1 behaviour left, but just incase...

	if (newBehaviours.getSize() < 1)
		return NULL;

	//return final behaviour from newBehaviours.  Null first, so not deleted during newBehaviours list deconstruction
	//Add event to final behaviour
	Behaviour* finalBehaviour = newBehaviours.getAt(0);
	finalBehaviour->setEvent(_event);
	newBehaviours.nullWithoutRemoving(0);
	return finalBehaviour;

}





int Character::getBehaviourInternalPriorityValue(BehaviourTypes _type)
{
	for (int i = 0; i < numberOfBehaviours; i++)
	{
		if (behavioursAvailable[i].behaviourType == _type)
			return behavioursAvailable[i].priority;
	}

	return -1;
}


void Character::sortBehaviourListOnPriority(BehaviourList* _behaviours)
{
	BehaviourList tempList = BehaviourList();

	//pass 1 for Character priorities
	for (int j = 0; j < _behaviours->getSize(); j++)
	{
		Behaviour* tempBehaviour = NULL;
		int tempBehaviourID;

		for (int i = 0; i < _behaviours->getSize(); i++)
		{
			if (_behaviours->getAt(i) != NULL)
			{
				if (tempBehaviour == NULL)
				{
					tempBehaviour = _behaviours->getAt(i);
					tempBehaviourID = i;
				}
				else
				{
					if (getBehaviourInternalPriorityValue(tempBehaviour->getBehaviourType()) < getBehaviourInternalPriorityValue(_behaviours->getAt(i)->getBehaviourType()))
					{
						tempBehaviour = _behaviours->getAt(i);
						tempBehaviourID = i;
					}
				}
			}
		}
		tempList.add(tempBehaviour);
		_behaviours->nullWithoutRemoving(tempBehaviourID);
	}

	BehaviourList tempList2 = BehaviourList();

	//pass 2 for behaviour internal priorities
	for (int j = 0; j < _behaviours->getSize(); j++)
	{
		Behaviour* tempBehaviour = NULL;
		int tempBehaviourID;

		for (int i = 0; i < _behaviours->getSize(); i++)
		{
			if (tempList.getAt(i) != NULL)
			{
				if (tempBehaviour == NULL)
				{
					tempBehaviour = tempList.getAt(i);
					tempBehaviourID = i;
				}
				else
				{
					if (tempBehaviour->getBehaviourPriorityValue() < tempList.getAt(i)->getBehaviourPriorityValue())
					{
						tempBehaviour = tempList.getAt(i);
						tempBehaviourID = i;
					}
				}
			}
		}
		tempList2.add(tempBehaviour);
		tempList.nullWithoutRemoving(tempBehaviourID);
	}
	//Update old list with new order.  Null templist, so behaviours arn't deleted on list deconstruction
	for (int i = 0; i < tempList2.getSize(); i++)
	{
		_behaviours->setAt(i, tempList2.getAt(i));
		tempList2.nullWithoutRemoving(i);
	}

}